﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ZPod.MTG;
using ZPod.MTG.Windows.Properties;
using System.IO;

namespace ZPod.MTG.Windows
{
	public partial class CardPanel : UserControl
	{
		#region Private Properties

		//Listado de Carta : EstaGirada
		List<Pair<Card, Boolean>> _cards = new List<Pair<Card, Boolean>>();

		Dictionary<String, CardEvent> _contextualOptions = new Dictionary<string, CardEvent>();

		Dictionary<string, CardDetailEvent> _cardDetailContextualOptions = new Dictionary<string, CardDetailEvent>();
		
		#endregion

		#region Delegates

		public delegate void CardEvent(int cardIndex, CardPanel panel);
		public delegate void CardDetailEvent(Card currentCard, int cardIndex, CardPanel panel);

		#endregion

		#region Public Constructors

		public CardPanel()
		{
			InitializeComponent();

			CanControl = true;
		}

		#endregion

		#region Public Properties

		public Dictionary<String, CardEvent> ContextualOptions
		{
			get
			{
				return _contextualOptions;
			}
		}

		public bool CanControl
		{
			get;
			set;
		}

		public List<Card> Cards
		{
			get
			{
				return _cards.Select(elem => elem.First).ToList();
			}
		}

		public List<Pair<Card, Boolean>> CardsWithState
		{
			get
			{
				return new List<Pair<Card, bool>>(_cards);
			}
		}

		public Card this[int index]
		{
			get
			{
				return _cards[index].First;
			}
		}

		#endregion

		#region Public Methods

		#region AddCard

		public void AddCard(Card card)
		{
			AddCard(card, true);
		}

		public void AddCard(Card card, bool refresh)
		{
			AddCard(card, false, refresh);
		}

		public void AddCard(Card card, bool rotated, bool refresh)
		{
			_cards.Add(new Pair<Card, bool> { First = card, Second = rotated });
			if (refresh)
			{
				RefreshCards();
			}
		}

		#endregion

		#region AddCards

		public void AddCards(IEnumerable<Card> cards)
		{
			AddCards(cards, true);
		}

		public void AddCards(IEnumerable<Card> cards, bool refresh)
		{
			var straightCards = from c in cards select new Pair<Card, bool> { First = c, Second = false };

			AddCards(straightCards, refresh);
		}

		public void AddCards(IEnumerable<Pair<Card, Boolean>> cards, bool refresh)
		{
			foreach (var card in cards)
			{
				AddCard(card.First, card.Second, false);
			}

			if (refresh)
			{
				RefreshCards();
			}
		}

		#endregion

		public void RemoveCard(int index)
		{
			_cards.RemoveAt(index);
			RefreshCards();
		}

		public void Clear()
		{
			_cards.Clear();
			RefreshCards();
		}

		public void RotateCard(int index)
		{
			_cards[index].Second = true;
			RefreshCards();
		}

		public void StraightCard(int index)
		{
			_cards[index].Second = false;
			RefreshCards();
		}

		public void StraightAll()
		{
			foreach (var elem in _cards)
			{
				elem.Second = false;
			}

			RefreshCards();
		}

		public void RefreshCards()
		{
			//flowPanel.SuspendLayout();
			
			var pictureBoxes = flowPanel.Controls.OfType<PictureBox>();
			flowPanel.Controls.Clear();

			foreach (var control in pictureBoxes)
			{
				control.Image.Dispose();
				control.Dispose();
			}

			
			for (int i = 0; i < _cards.Count; i++)
			{
				var elem = _cards[i];
				PictureBox cardBox = new PictureBox();
				cardBox.Tag = i;

				if (CanControl)
				{
					var image = CardStorage.GetCardThumbnail(elem.First);
					// Si tiene cartas asociadas lo indico
					if (elem.First.AttachedCards.Count > 0)
					{
						/*
						Graphics graphic = Graphics.FromImage(image);
						Bitmap mark = Resources.Mark;
						var location = new Point(image.Height - mark.Height, image.Width - mark.Width);
						graphic.DrawImage(mark, location);

						using (var stream = new MemoryStream())
						{
							image.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
							image = Image.FromStream(stream);
						}
						*/
					}

					ToolTip toolTip = new ToolTip();
					toolTip.SetToolTip(cardBox, elem.First.Name);

					cardBox.ImageLocation = image;

					cardBox.MouseEnter += ((o, e) => CurrentCardDialog.SetCard(elem.First));
					cardBox.DoubleClick += new EventHandler(cardBox_DoubleClick);

					if (ContextualOptions.Count > 0)
					{
						ContextMenu menu = new ContextMenu();
						
						foreach (var kvp in ContextualOptions)
						{
							CardContextMenuItem item = new CardContextMenuItem();
							item.CardIndex = i;
							item.Method = kvp.Value;
							item.Text = kvp.Key;
							item.Click += new EventHandler(item_Click);
							menu.MenuItems.Add(item);
						}

						cardBox.ContextMenu = menu;
					}
				}
				else //Si no lo puedo controlar, solo muestro cartas genericas
				{
					cardBox.ImageLocation = CardStorage.GetGenericCard();
				}

				cardBox.SizeMode = PictureBoxSizeMode.Zoom;
				cardBox.Load();
				flowPanel.Controls.Add(cardBox);
				//cardBox.LoadAsync();
				//cardBox.LoadCompleted += new AsyncCompletedEventHandler(new LoadCompleteHandler() {elem =elem, flowPanel = flowPanel}.cardBox_LoadCompleted);


				int size = flowPanel.Height - 25;
				cardBox.Height = size;
				cardBox.Width = Convert.ToInt32((double)size / (double)cardBox.Image.Height * cardBox.Image.Width);

				if (elem.Second) //Girada
				{
					cardBox.Image.RotateFlip(RotateFlipType.Rotate90FlipNone);

					// Swap
					int temp = cardBox.Height;
					cardBox.Height = cardBox.Width;
					cardBox.Width = temp;
				}

				cardBox.Padding = new Padding(3);	
			}

			//flowPanel.ResumeLayout();
		}

		public void AddCardDetailContextualOption(string title, CardDetailEvent handler)
		{
			_cardDetailContextualOptions.Add(title, handler);
		}

		public void ClearCardDetailContextualOptions()
		{
			_cardDetailContextualOptions.Clear();
		}

		#endregion

		#region Private Methods

		#region Event Handlers

		void item_Click(object sender, EventArgs e)
		{
			var menuItem = (CardContextMenuItem)sender;

			menuItem.Method(menuItem.CardIndex, this);
		}

		void cardBox_DoubleClick(object sender, EventArgs e)
		{
			var cardBox = (PictureBox)sender;
			var id = (int)cardBox.Tag;

			ShowCardDetail(id);
		}

		#endregion 

		#region Support Methods

		private void ShowCardDetail(int index)
		{
			var selectedCard = _cards[index].First;
			using (CardDetailDialog dialog = new CardDetailDialog(selectedCard))
			{
				foreach (var kvp in _cardDetailContextualOptions)
				{
					var handler = new CardDetailContextualMenuHandler(selectedCard, kvp.Value);
					dialog.AddContextualOption(kvp.Key, handler.Handle);
				}

				dialog.RefreshCards();
				dialog.ShowDialog();
			}
		}

		#endregion

		#endregion

		#region Support Classes

		private class CardContextMenuItem : MenuItem
		{
			public int CardIndex;
			public CardEvent Method;
		}

		private class CardDetailContextualMenuHandler
		{
			public CardDetailContextualMenuHandler(Card card, CardDetailEvent realHandler)
			{
				CurrentCard = card;
				RealHandler = realHandler;
			}

			public Card CurrentCard
			{
				get;
				set;
			}

			public CardDetailEvent RealHandler
			{
				get;
				set;
			}

			public void Handle(int cardIndex, CardPanel panel)
			{
				RealHandler(CurrentCard, cardIndex, panel);
			}
		}

		#endregion

		
	}
}
